package top.eggcode.security.shiro;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.filter.AccessControlFilter;
import top.eggcode.common.mvc.HttpResponseUtil;
import top.eggcode.common.mvc.ResultStatus;
import top.eggcode.common.mvc.ResultWrapper;
import top.eggcode.security.TokenRefreshException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Title: 检查Token
 * Description: 用户必须携带登录标识
 * Date: 2021/4/17 20:05
 *
 * @author JiaQi Ding
 * @version 1.0
 */
public class TokenFilter extends AccessControlFilter {

    /**
     * 是否允许访问
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) {

        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        if ("OPTIONS".equals(httpRequest.getMethod())) {
            return true;
        }

        // 会话标识
        String token = httpRequest.getHeader("X-Authorization");

        if (StringUtils.isEmpty(token)) {

            // 未携带Token
            HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                    ResultWrapper.failure(ResultStatus.REQ_NO_TOKEN));
            // 拒绝访问
            return false;
        }

        // 认证身份
        try {
            getSubject(servletRequest, servletResponse).login(new SessionToken(token));
        } catch (AuthenticationException e) {
            if (e instanceof IncorrectCredentialsException) {
                // 无效token
                HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                        ResultWrapper.failure(ResultStatus.USER_INVALID_TOKEN));
            } else if (e instanceof ExpiredCredentialsException) {
                // token 过期
                HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                        ResultWrapper.failure(ResultStatus.USER_OVERDUE_TOKEN));
            } else if (e instanceof UnknownAccountException) {
                // 用户不存在
                HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                        ResultWrapper.failure(ResultStatus.USER_ACCOUNT_NOT_FOUND));
            } else if (e instanceof TokenRefreshException) {
                // token 需要刷新
                HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                        ResultWrapper.failure(ResultStatus.USER_TOKEN_REFRESH));
            } else {
                // token 过期
                HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                        ResultWrapper.failure(ResultStatus.USER_AUTHORIZATION_FAIL));
            }
            // 拒绝访问
            return false;
        }

        return true;
    }

    /**
     * 访问拒绝后的处理（isAccessAllowed 返回 false）
     * true 让过滤链继续执行，false 请求结束
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) {

        // 请求结束
        return false;
    }
}
